package com.wei.czz.common.aspect;

import com.wei.czz.common.constant.Constant;
import com.wei.czz.framework.common.service.SnowflakeService;
import com.wei.czz.framework.rabbitMQ.message.BaseMessage;
import lombok.AllArgsConstructor;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;

import java.util.Optional;
import java.util.stream.Stream;

/**
 * Created by IntelliJ IDEA.
 *
 * @author wyw
 * date: 2024-11-29 16:16:39
 * className: MqListenerAspect rabbitMQ消息监听切片类
 * version: 1.0
 * description:
 */
@Aspect
@Component
@AllArgsConstructor
public class MqListenerAspect {

    private static final Logger log = LoggerFactory.getLogger(MqListenerAspect.class);

    private final SnowflakeService snowflakeService;

    /**
     * 使用RabbitListener方法
     */
    @Pointcut("@annotation(org.springframework.amqp.rabbit.annotation.RabbitListener)")
    public void annotationPoint() {}

    /**
     * Aop环绕通知方法
     */
    @Around("annotationPoint()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        // 从消息对象中获取链路追踪值
        Optional<String> optional = Stream.of(pjp.getArgs())
                .filter(arg -> arg instanceof BaseMessage)
                .map(arg -> (BaseMessage) arg)
                .findFirst()
                .map(BaseMessage::getTraceId);
        if (optional.isPresent()) {
            String traceId = optional.get();
            log.info("消息对象携带的链路追踪值: {}", traceId);
        }

        // 增加日志链路追踪代码
        String traceId = Long.toHexString(snowflakeService.get());
        MDC.put(Constant.TRACE_ID, optional.orElse(traceId));
        MDC.put(Constant.SPAN_ID, traceId);
        try {
            // 执行目标方法
            return pjp.proceed();
        } catch (Throwable e) {
            log.error("消费者消费消息异常。message={}", e.getMessage(), e);
            throw e;
        } finally {
            MDC.clear();
        }
    }

}
